from datetime import datetime, timedelta
from typing import Optional, Annotated

from fastapi import APIRouter, Depends, status as HttpStatus, Response, Header
from sqlalchemy.orm import Session
import requests
from utils.response import HTTPException
import config
from db import get_db, crud
from schemas.customer import CustomerLoginRequest, CreateCustomerRequest, CustomerLoginResponse, CustomerModel, \
    UpdateCustomerInfoRequest, UpdateCustomerInfoResponse, CustomerRefreshTokenResponse
from config import WEIXIN_APP_ID, WEIXIN_APP_SECRET
import jwt
from jwt import DecodeError

router = APIRouter(prefix="/customer", tags=["客户管理"])


async def verify_customer_token(authorization: Optional[str] = Header(None),
                                db: Session = Depends(get_db)) -> CustomerModel:
    try:
        data = jwt.decode(authorization, config.CUSTOMER_SECRET_KEY, algorithms=[config.ALGORITHM])
        customer = crud.Customer.get(db, data["user_id"])
        if customer is None:
            raise HTTPException(
                http_code=HttpStatus.HTTP_401_UNAUTHORIZED,
                detail={"msg": "用户不存在"}
            )
        return CustomerModel.from_orm(customer)
    except DecodeError:
        raise HTTPException(
            http_code=HttpStatus.HTTP_401_UNAUTHORIZED,
            detail={"msg": "Token验证失败"}
        )


def get_weixin_user_openid(code: str) -> str:
    res = requests.get("https://api.weixin.qq.com/sns/jscode2session", {
        "appid": WEIXIN_APP_ID,
        "secret": WEIXIN_APP_SECRET,
        "js_code": code,
        "grant_type": "authorization_code"
    })

    return res.json()["openid"]


def get_token(user_id: int, openid: str) -> str:
    access_expire = datetime.now() + timedelta(seconds=config.CUSTOMER_TOKEN_EXPIRE)
    access_claims = {"user_id": user_id, "openid": openid, "iss": "server", "sub": "access token", "exp": access_expire}
    access_token = jwt.encode(access_claims, config.CUSTOMER_SECRET_KEY, algorithm=config.ALGORITHM)

    return access_token


@router.post("/login", response_model=CustomerLoginResponse, response_model_exclude_none=True)
def login(data: CustomerLoginRequest, db: Session = Depends(get_db)):
    openid = get_weixin_user_openid(data.code)
    customer = crud.Customer.get_by_openid(db, openid)

    if customer is None:
        customer = crud.Customer.create(db, CreateCustomerRequest(
            created_on=datetime.now(),
            openid=openid
        ))

    customer.last_login_time = datetime.now()

    db.commit()

    expire = datetime.now() + timedelta(seconds=config.CUSTOMER_TOKEN_EXPIRE)

    return CustomerLoginResponse(
        id=customer.id,
        created_on=customer.created_on,
        openid=customer.openid,
        nickname=customer.nickname,
        avatar=customer.avatar,
        phone=customer.phone,
        gender=customer.gender,
        level=customer.level,
        last_login_time=customer.last_login_time,
        expires=int(expire.timestamp() * 1000),
        token=get_token(customer.id, customer.openid)
    )


@router.post("/refresh-token", response_model=CustomerRefreshTokenResponse, response_model_exclude_none=True)
def refresh_token(db: Session = Depends(get_db), customer: CustomerModel = Depends(verify_customer_token)):
    data = crud.Customer.get(db, customer.id)

    data.last_login_time = datetime.now()
    db.commit()

    expire = datetime.now() + timedelta(seconds=config.CUSTOMER_TOKEN_EXPIRE)

    return CustomerRefreshTokenResponse(
        id=customer.id,
        created_on=customer.created_on,
        openid=customer.openid,
        nickname=customer.nickname,
        avatar=customer.avatar,
        phone=customer.phone,
        gender=customer.gender,
        level=customer.level,
        last_login_time=customer.last_login_time,
        expires=int(expire.timestamp() * 1000),
        token=get_token(customer.id, customer.openid)
    )


@router.get("/info")
def get_customer_info(token: Optional[str] = Header(None)):
    print(token)
    return Response()


@router.put("/info", response_model=UpdateCustomerInfoResponse, response_model_exclude_none=True)
def update_customer_info(data: UpdateCustomerInfoRequest,
                         customer: CustomerModel = Depends(verify_customer_token),
                         db: Session = Depends(get_db)):
    data.id = customer.id

    result = crud.Customer.update_info(db, data)
    if result is not None:
        return UpdateCustomerInfoResponse(
            id=result.id,
            nickname=result.nickname,
            avatar=result.avatar,
            phone=result.phone,
            gender=result.gender,
        )
    return HTTPException()


@router.get("/like/article-comment")
def get_like_article_comment(customer: CustomerModel = Depends(verify_customer_token),
                             db: Session = Depends(get_db)):
    data = crud.ArticleCommentLike.get_by_customer(db, customer.id)
    result = []
    for item in data:
        result.append(item.comment_id)

    return result


@router.get("/like/article")
def get_like_article(customer: CustomerModel = Depends(verify_customer_token),
                     db: Session = Depends(get_db)):
    data = crud.ArticleLike.get_by_customer(db, customer.id)
    result = []
    for item in data:
        result.append(item.article_id)

    return result
